package com.kpmg.datalake.common.service.impl;

import com.kpmg.datalake.common.dao.UserManagementMapper;
import com.kpmg.datalake.common.enums.ResultCodeEnum;
import com.kpmg.datalake.common.enums.SystemParamsEnum;
import com.kpmg.datalake.common.model.UserInfo;
import com.kpmg.datalake.common.service.IComSystemParamsService;
import com.kpmg.datalake.common.service.UserManagementService;
import com.kpmg.datalake.common.utils.AssertUtil;
import com.kpmg.datalake.common.utils.EncrypUtil;
import com.kpmg.datalake.common.vo.ServerResponse;
import com.kpmg.datalake.common.vo.UserLoginDTO;
import com.kpmg.datalake.common.vo.UserManagementDTO;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/**
 * @Auther: Richard.ji [richard.ji@kpmg.com]
 * @Date: 2018-07-06 10:07:36
 * @Description:  用户管理
 */
@Service
public class UserManagementServiceImpl implements UserManagementService {

  private static final Logger logger = LoggerFactory.getLogger(UserManagementServiceImpl.class);

  private static final String DEFAULT_SYS_LOGIN_LOCK_TIME = "5";

  private static final String DEFAULT_SYS_FREEZE_SECONDS = "60";

  @Resource
  private UserManagementMapper userManagementMapper;

  @Resource
  private IComSystemParamsService iComSystemParamsService;

  /*
   *  获取用户信息
   */
  @Override
  public ServerResponse getUserInfoList(UserManagementDTO userInfoDTO) {
    List<UserInfo> userInfoList = userManagementMapper.getUserInfoList(userInfoDTO);

    ArrayList<UserManagementDTO> userDtoList = new ArrayList<>();

    UserManagementDTO userManagementDTO = new UserManagementDTO();
    if (!CollectionUtils.isEmpty(userInfoList)) {
      userInfoList.forEach(userInfo -> {
        BeanUtils.copyProperties(userInfo, userManagementDTO);
        userDtoList.add(userManagementDTO);
      });

      return ServerResponse.createBySuccess("获取用户信息成功", userDtoList);
    } else {
      return ServerResponse.createBySuccess("获取用户信息成功", userDtoList);
    }
  }

  /*
   *  保存用户信息
   */
  @Override
  public ServerResponse saveUser(UserManagementDTO userInfoDTO) {
    String password = userInfoDTO.getPassword();

    if (password.length() != 64) {
      userInfoDTO.setPassword(EncrypUtil.encryptSha256(password));
    }

    int userCode = userManagementMapper.saveUser(convertDTO(userInfoDTO));

    return ServerResponse.createBySuccess("保存用户信息成功", userCode);
  }

  /*
   *  修改用户信息
   */
  @Override
  public ServerResponse updateUser(UserManagementDTO userInfoDTO) {

    int userCode = userManagementMapper.updateUser(convertDTO(userInfoDTO));

    return ServerResponse.createBySuccess("修改用户信息成功", userCode);
  }

  /*
   *  删除用户信息
   */
  @Override
  public ServerResponse deleteUser(UserManagementDTO userInfoDTO) {

    int userCode = userManagementMapper.updateUser(convertDTO(userInfoDTO));

    return ServerResponse.createBySuccess(" 删除用户信息成功", userCode);
  }

  private UserInfo convertDTO(UserManagementDTO userManagementDTO) {
    UserInfo userInfo = new UserInfo();
    BeanUtils.copyProperties(userManagementDTO, userInfo);

    return userInfo;
  }

  @Override
  public ServerResponse<String> updateUserLoginDetail(String userName, String loginIp,
      Boolean loginSuccess) {
    AssertUtil.assertNotEmpty(userName, "用户名不能为空");
    AssertUtil.assertNotEmpty(loginIp, "登陆IP不能为空");
    UserLoginDTO cacheUserLogin = ((UserManagementServiceImpl) AopContext.currentProxy())
        .getUserLogin(userName, loginIp);

    if (loginSuccess) {
      cacheUserLogin.setFailedNumber(0);
      ((UserManagementServiceImpl) AopContext.currentProxy()).saveUserLoginInfo(cacheUserLogin);
      return ServerResponse.createBySuccessMessage(ResultCodeEnum.CODE0000.getDisplay());
    } else {
      int failedLoginTime = cacheUserLogin.getFailedNumber();
      String maxSysFailedTime = iComSystemParamsService
          .getSystemParamsByCode(SystemParamsEnum.MAX_CONTINUOUS_LOGIN_FAILED_TIME.getCode(),
              DEFAULT_SYS_LOGIN_LOCK_TIME);
      logger.info("用户{}从IP:{}先前登陆失败{}次", userName, loginIp, failedLoginTime);
      Date currentDate = new Date();
      long currentTime = currentDate.getTime();
      if (failedLoginTime >= Integer.parseInt(maxSysFailedTime)) {
        long latestFailedTime = cacheUserLogin.getLatestFailedTime().getTime();
        long unfreezeSeconds = Long.parseLong(iComSystemParamsService
            .getSystemParamsByCode(SystemParamsEnum.UNFREEZE_LOCK_USER_SECONDS.getCode(),
                DEFAULT_SYS_FREEZE_SECONDS)) * 1000;
        if (currentTime - latestFailedTime >= unfreezeSeconds) {
          logger.info("用户{}在IP:{}锁定状态时间已过, 但没有成功登陆, 重新开始记录失败次数", userName, loginIp);
          cacheUserLogin.setFailedNumber(1);
          cacheUserLogin.setLatestFailedTime(currentDate);
        }
      } else {
        cacheUserLogin.increaseFailedTime();
        cacheUserLogin.setLatestFailedTime(currentDate);
        logger.info("用户{}从IP:{}登陆失败次数增加为{}", userName, loginIp, cacheUserLogin.getFailedNumber());
      }
      ((UserManagementServiceImpl) AopContext.currentProxy()).saveUserLoginInfo(cacheUserLogin);
      return ServerResponse
          .createByErrorCodeMessage(ResultCodeEnum.CODE4018, ResultCodeEnum.CODE4018.getDisplay());
    }
  }

  @Override
  public ServerResponse<String> checkUserLoginStatus(String userName, String loginIp) {
    AssertUtil.assertNotEmpty(userName, "userName不能为空");
    AssertUtil.assertNotEmpty(loginIp, "loginIP不能为空");
    UserLoginDTO cacheUserLogin = ((UserManagementServiceImpl) AopContext.currentProxy())
        .getUserLogin(userName, loginIp);
    int failedLoginTime = cacheUserLogin.getFailedNumber();
    String maxSysFailedTime = iComSystemParamsService
        .getSystemParamsByCode(SystemParamsEnum.MAX_CONTINUOUS_LOGIN_FAILED_TIME.getCode(),
            DEFAULT_SYS_LOGIN_LOCK_TIME);

    // 用户登录失败次数超过系统配置次数，且当前登陆时间和最近的登陆失败时间的间隔没有超过系统配置的解冻时间，此时用户为锁定状态
    if (failedLoginTime >= Integer.parseInt(maxSysFailedTime)) {
      Date currentDate = new Date();
      long currentTime = currentDate.getTime();
      long latestFailedTime = cacheUserLogin.getLatestFailedTime().getTime();
      long unfreezeSeconds = Long.parseLong(iComSystemParamsService
          .getSystemParamsByCode(SystemParamsEnum.UNFREEZE_LOCK_USER_SECONDS.getCode(),
              DEFAULT_SYS_FREEZE_SECONDS)) * 1000;
      if (currentTime - latestFailedTime
          < unfreezeSeconds) {
        return ServerResponse
            .serverResponse(ResultCodeEnum.CODE4042, new Object[]{maxSysFailedTime}, null);
      }
    }
    return ServerResponse.createBySuccess();
  }

  @Cacheable(value = "userLogin", key = "#userName+':'+#loginIp")
  public UserLoginDTO getUserLogin(String userName, String loginIp) {
    logger.info("从缓存中获取信息, 只有第一次会执行方法本身");
    return new UserLoginDTO(userName, loginIp);
  }

  @CachePut(value = "userLogin", key = "#userLoginDTO.getUserName()+':'+#userLoginDTO.getLoginIp()")
  public UserLoginDTO saveUserLoginInfo(UserLoginDTO userLoginDTO) {
    AssertUtil.assertNotEmpty(userLoginDTO.getUserName(), "用户名不能为空");
    AssertUtil.assertNotEmpty(userLoginDTO.getLoginIp(), "登陆IP不能为空");
    logger.info("保存用户{}登陆信息到缓存", userLoginDTO.getUserName());
    return userLoginDTO;
  }
}
